// canvas 点类
class Points {
  x: number = 0;
  y: number = 0;
  color: string = "#000000";
  size: number = 1;
  xSpeed: number = 0;
  ySpeed: number = 0;
  lastDrawTime: number | null = 0;

  // 构造函数
  constructor(x: number, y: number, color: string, size: number) {
    this.x = x;
    this.y = y;

    this.color = color;
    this.size = size;

    // 随机移动
    this.xSpeed = Points.getRandom(-50, 50);
    this.ySpeed = Points.getRandom(-50, 50);
    // 时间
    this.lastDrawTime = null;
  }
  // 绘制圆点
  draw(ctx?: CanvasRenderingContext2D | null): void {
    if (!ctx) return;
    // 限制帧率

    if (this.lastDrawTime) {
      const now = Date.now();
      const t = (now - this.lastDrawTime) / 1000;

      this.x += this.xSpeed * t;
      this.y += this.ySpeed * t;

      if (this.x <= this.size || this.x >= ctx.canvas.width - this.size) {
        this.xSpeed *= -1;
      }
      if (this.y <= this.size || this.y >= ctx.canvas.height - this.size) {
        this.ySpeed *=-1;
      }
    }
    // if (ctx) {
    ctx.beginPath();
    // 绘制圆点 - 圆心坐标，半径，起始角度，终止角度，弧度制
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.closePath();
    // }
    this.lastDrawTime = Date.now();
  }

  // 工具函数
  public static getRandom(min: number, max: number): number {
    return Math.floor(Math.random() * (max + 1 - min) + min);
  }
}


// canvas 背景类
export class Background {
  canvas: HTMLCanvasElement;
  ctx2d: CanvasRenderingContext2D | null = null;
  private points: Points[] = [];
  // 最大距离
  private maxDis: number = 100;

  constructor(
    canvas: HTMLCanvasElement,
    num: number = 50,
    maxDis: number = 300
  ) {
    this.canvas = canvas;
    this.ctx2d = canvas.getContext("2d");
    this.maxDis = maxDis;
    // 适配 dpr
    this.adaptDPR();
    this.generatePoints(num);
    // this.generatePoints(num);
    // 绘制背景
    // this.draw(this.ctx2d);
  }

  // 生成点
  private generatePoints(num: number): void {
    const w = this.canvas.width;
    const h = this.canvas.height;
    // 随机生成 50 个点
    // const num = 50;

    for (let i = 0; i < num; i++) {
      // 点大小
      const size = 5;
      // 随机生成坐标
      const x = Points.getRandom(0, w - size / 2);
      const y = Points.getRandom(0, h - size / 2);
      // 随机生成颜色
      const color = this.randomColor();
      // const color = `rgb(200,200,200)`;

      // 创建点
      const point = new Points(x, y, color, size);
      // 加入数组
      this.points.push(point);
    }
  }

  // 方法一：放大画布之后，直接用 scale 放大整个坐标系
  // * 但是你要知道我们一直是在放大的坐标系上绘制的，可能不知道什么时候（比如重新设置画布宽高），scale 可能就会被重置成 1 了，从而造成画面错乱
  adaptDPR() {
    // 在初始化 canvas 的时候就要调用该方法
    const dpr = window.devicePixelRatio;
    const width = window.innerWidth;
    const height = window.innerHeight;

    // 重新设置 canvas 自身宽高大小和 css 大小。放大 canvas；css 保持不变，因为我们需要那么多的点
    this.canvas.width = Math.round(width * dpr);
    this.canvas.height = Math.round(height * dpr);

    // 直接用 scale 放大整个坐标系，相对来说就是放大了每个绘制操作
    // this.ctx2d?.scale(dpr, dpr);
  }

  // 绘制背景
  draw(): void {
    // 动画
    requestAnimationFrame(() => {
      this.draw();
    });
    const ctx = this.ctx2d;
    if (!ctx) return;
    // 清空画布
    ctx?.clearRect(0, 0, this.canvas.width, this.canvas.height);
    // 绘制背景色
    ctx.fillStyle = "rgba(0, 0, 0, 1)";

    // 绘制点
    for (let i = 0; i < this.points.length; i++) {
      const point = this.points[i];
      point.draw(ctx);
    }
    // 和其他所有点链接线
    for (let i = 0; i < this.points.length; i++) {
      const point = this.points[i];
      for (let j = i + 1; j < this.points.length; j++) {
        const point2 = this.points[j];
        // 计算距离
        const dis = Math.sqrt(
          Math.pow(point.x - point2.x, 2) + Math.pow(point.y - point2.y, 2)
        );
        // 限制最大距离
        if (dis > this.maxDis) continue;
        // 绘制线
        ctx?.beginPath();
        ctx?.moveTo(point.x, point.y);
        ctx?.lineTo(point2.x, point2.y);
        // 线颜色
        ctx.strokeStyle = `rgba(100, 100, 100, ${
          (1 - dis / this.maxDis) * 0.5
        })`;
        ctx?.stroke();
        ctx?.closePath();
      }
    }
  }

  // 随机颜色
  private randomColor(): string {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    return `rgb(${r},${g},${b})`;
    // return `rgb(200,200,200)`
  }
}
